package figure8;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.sound.midi.Instrument;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiChannel;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Patch;
import javax.sound.midi.Receiver;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.Synthesizer;
import javax.sound.midi.Transmitter;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.BooleanControl;
import javax.sound.sampled.Clip;
import javax.sound.sampled.CompoundControl;
import javax.sound.sampled.Control;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.EnumControl;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.Port;
import javax.sound.sampled.TargetDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JOptionPane;

import figure8.GUI.AudioInputWindow;
import figure8.GUI.EffectWindow;
import figure8.GUI.MainWindow;
import figure8.GUI.RecMIDISelectInstrumentWindow;
import figure8.Track.Type;
import figure8.events.PlaybackEvent;

public class Rec extends Thread {
	private AudioFileFormat.Type m_targetType;
	private String m_outputFile;
	private int wavTrackNum, midiTrackNum, instrumentNumber;
	private ArrayList<File> outputFileA, outputFileB, MIDIoutputFileA,
			MIDIoutputFileB;
	private int current, recordingNum, pressed, setup;
	private Synthesizer synth;
	private Sequencer seq;
	private MIDIRecorder midiRecorder;
	private Sequence sequence;
	private Receiver synthRcvr;
	private javax.sound.midi.Track midiCurrent;
	private TargetDataLine targetDataLine;
	private Boolean stop, rec, midi, wav, drumMachine;
	private Thread mainRecord;
	
	public static Mixer mixerPlay;

	private Controller controller;
	private LoopTiming timing;

	private static AudioFormat format;
	public static DataLine.Info info;

	private File projectDir;

	// I have reverted this, please re-add any changes you made.
	
	private static float sampleRates[] = {44100, 16000, 11025, 8000};
	
	static {
		Mixer.Info[] mixers = AudioSystem.getMixerInfo();

		Pattern pattern = null;
		Matcher matcher;
		int mixerSelector = 0;
		int count = 0;
		for ( Mixer.Info mix : Rec.getOutputMixers())
		{
			pattern = pattern.compile("Java Sound Audio Engine");
			matcher = pattern.matcher(mix.toString());
			if (matcher.find()){
				mixerSelector = count;
				System.out.println("Mixer chosen: " + mixerSelector);
			}
			count++;
		}
		mixerPlay = AudioSystem.getMixer(Rec.getOutputMixers()[mixerSelector]);
		
		float sampleRate = 16000.0F;
		// 8000,11025,16000,22050,44100
		int sampleSizeInBits = 16;
		// 8,16
		int channels = 1;
		// 1,2
		boolean signed = true;
		// true,false
		boolean bigEndian = false;
		// true,false
		format = new AudioFormat(sampleRate, sampleSizeInBits, channels,
				signed, bigEndian);
		info = new DataLine.Info(Clip.class, format);
	}
	

	public static InputMixer[] getInputMixers() {
		ArrayList<InputMixer> mixers = new ArrayList<InputMixer>();

		for (Mixer.Info mixerInfo : AudioSystem.getMixerInfo()) {
			Mixer mixer = AudioSystem.getMixer(mixerInfo);
			
			for (float sampleRate : Rec.sampleRates) {
				int sampleSizeInBits = 16;
				int channels = 1;
				boolean signed = true;
				boolean bigEndian = false;
				
				AudioFormat format = new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
				
				DataLine.Info dataLineInfo = new DataLine.Info(
						TargetDataLine.class, format);
				
				InputMixer testMixer = new InputMixer(mixerInfo.getName(), mixer, format);
				
				try {
					TargetDataLine targetDataLine = testMixer.dataLine();
				} catch (LineUnavailableException e) {
					//System.err.println("Ignoring mixer " + mixerInfo.getName() + " (Line Unavailable).");
					continue;
				} catch (IllegalArgumentException e) {
					//.err.println("Ignoring mixer " + mixerInfo.getName() + " (Illegal).");
					continue;
				}
				
				//System.err.println("Found input mixer: " + mixerInfo.getName() + " (" + sampleRate + "Hz)");

				mixers.add(testMixer);
				
				break;
			}
		}

		return mixers.toArray(new InputMixer[mixers.size()]);
	}

	public static Mixer.Info[] getOutputMixers() {
		ArrayList<Mixer.Info> mixers = new ArrayList<Mixer.Info>();
		
		for (Mixer.Info mixerInfo : AudioSystem.getMixerInfo()) {
			Mixer mixer = AudioSystem.getMixer(mixerInfo);
			
			for (float sampleRate : Rec.sampleRates) {
				int sampleSizeInBits = 16;
				int channels = 1;
				boolean signed = true;
				boolean bigEndian = false;
				
				AudioFormat format = new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
				
				DataLine.Info dataLineInfo = new DataLine.Info(
						Clip.class, format);
				
				try {
					Clip clip = (Clip) mixer
							.getLine(dataLineInfo);
				} catch (LineUnavailableException e) {
					//System.err.println("Ignoring mixer " + mixerInfo.getName() + " (Line Unavailable).");
					continue;
				} catch (IllegalArgumentException e) {
					//.err.println("Ignoring mixer " + mixerInfo.getName() + " (Illegal).");
					continue;
				}
				
				//System.err.println("Found output mixer: " + mixerInfo.getName() + " (" + sampleRate + "Hz)");
				mixers.add(mixerInfo);
				
				break;
			}
		}
		return mixers.toArray(new Mixer.Info[mixers.size()]);
	}
	
	public Rec(Controller controller, String file, LoopTiming timing, File directory, DrumMachineTrack drum) {
		this.controller = controller;
		this.timing = timing;
		this.projectDir = directory;
		if (drum != null) this.controller.getProject().addTrack(drum);
		m_targetType = AudioFileFormat.Type.WAVE;
		// the beginning of the name of the output files (track number and
		// version get concat on the end later)
		m_outputFile = file;
		// the number of the track that is currently being recorded
		wavTrackNum = 0;
		midiTrackNum = 0;
		// basically figure8 records one wav and keeps that until the next one
		// has been recorded
		// thus we need two wavs files at any given time, one is called
		// (file+wavTrackNum) + A and the other
		// B. To know which one to use this int alternates between 0 and 1. If
		// keep is pressed when
		// current == 0 then B if current == 1, A is saved
		current = 0;
		// if keep has been pressed during current recording pressed == 1
		pressed = 0;
		// this is used to keep track of the total number of recordings made in
		// the current track layer
		recordingNum = 0;
		// this is used to check if the recording lines have been setup
		setup = 0;
		stop = false;
		rec = false;
		midi = false;
		wav = false;
		drumMachine = false;
		// two files for each track are created
		// record() records on A then B, then A etc so that when enter is
		// pressed
		// a track is made out of the one that isn't being recorded onto
		outputFileA = new ArrayList<File>();
		outputFileB = new ArrayList<File>();
		MIDIoutputFileA = new ArrayList<File>();
		MIDIoutputFileB = new ArrayList<File>();
		outputFileA.add(new File( this.projectDir + "/Recordings/" + m_outputFile
				+ "A0" + ".wav"));
		outputFileB.add(new File(this.projectDir + "/Recordings/" + m_outputFile
				+ "B0" + ".wav"));
		MIDIoutputFileA.add(new File(this.projectDir + "/Recordings/" + m_outputFile
				+ "A0" + ".mid"));
		MIDIoutputFileB.add(new File(this.projectDir + "/Recordings/" + m_outputFile
				+ "B0" + ".mid"));
		// get the file format (set out in a function below if we want to change
		// it from a menu in GUI later on)
		// an array to hold the list of available mixers in the system
		// this means that the java audio engine will be used to playback
		// as that is always the first one that getMixerInfo finds
		// creates what is basically a template for a data line that uses our
		// audioFormat and implements the
		// clip class
		// creates the array of 10 A and B files, means a max of ten tracks atm
		// which to be honest is
		// reasonable at the moment. These files won't appear in directory until
		// written too
		if (drum == null) this.controller.getProject().addTrack(new DrumMachineTrack(this.controller.getProject().getTiming()));
		//this.controller.getProject().addTrack(drumMachineTrack.get(drumMachineTrack.size() - 1));
		//this.controller.getProject().addTrack(drumMachineTrack.get(0));
	}
		
	//Constructor for setting up Rec when loading project from file
	public Rec(Controller controller, LoopTiming timing, File directory, String file, Project project, DrumMachineTrack drumTrack) {
		this.controller = controller;
		this.timing = timing;
		this.projectDir = directory;
		m_targetType = AudioFileFormat.Type.WAVE;
		m_outputFile = file;
		outputFileA = new ArrayList<File>();
		outputFileB = new ArrayList<File>();
		MIDIoutputFileA = new ArrayList<File>();
		MIDIoutputFileB = new ArrayList<File>();
		//wavTrack = new ArrayList<WAVTrack>();
		//midiTrack = new ArrayList<MIDITrack>();
		//drumMachineTrack = new ArrayList<DrumMachineTrack>();
		DrumMachineTrack newDrumTrack = null;
		if (drumTrack != null) newDrumTrack = drumTrack;
		wavTrackNum = 0;
		midiTrackNum = 0;
		ArrayList<File> filesKeep = new ArrayList<File>();
		try {
			BufferedReader reader = new BufferedReader(new FileReader(new File(directory + 
					File.separator + "list_tracks.f8p")));
			ObjectInputStream stream = null;
			String nextLine;
			while((nextLine = reader.readLine()) != null) {
				nextLine.trim();
				StringTokenizer recVarTok = new StringTokenizer(nextLine, ",");
				String nextFile = recVarTok.nextToken();
				float vol = Float.parseFloat(recVarTok.nextToken());
				File trackFile;
				if(nextFile.startsWith(
						directory.getAbsolutePath()) == false) {
					//allows you to move a project folder and this will correct
					//the paths in the list_tracks file.
					int index = nextFile.lastIndexOf(File.separator);
					String newPath = directory.getAbsolutePath() + File.separator;
					if(nextFile.endsWith("drum_machine.f8p") == false) {
						newPath = newPath + "Recordings" + File.separator;
					}
					newPath = newPath + nextFile.substring(index);
					trackFile = new File(newPath);
				}
				else {
					trackFile = new File(nextFile);
				}
				if(trackFile.getAbsolutePath().endsWith("drum_machine.f8p")) {
					stream = new ObjectInputStream(new FileInputStream(trackFile));
					Boolean[][] drum = (Boolean[][]) stream.readObject();
					if (newDrumTrack == null) {
						newDrumTrack = new DrumMachineTrack(this.controller.getProject().getTiming(), drum);
					}
					newDrumTrack.switchProject(this.controller.getProject().getTiming(), drum);
					this.drumMachine = true;
					int kitNum = Integer.parseInt(recVarTok.nextToken());
					newDrumTrack.changeKit(kitNum);
					newDrumTrack.setVolume(vol);
					this.controller.getProject().addTrack(newDrumTrack);
					stream.close();
				}
				else {
					filesKeep.add(trackFile);
					if(trackFile.getAbsolutePath().endsWith(".wav")) {
						WAVTrack track = new WAVTrack((Clip) 
								mixerPlay.getLine(info),trackFile, this.timing);
						track.setVolume(vol);
						if(recVarTok.hasMoreTokens()) {
							String eff = recVarTok.nextToken();
							track.setEffChain(eff);
							new EffectWindow(controller, track, eff.split(";"));
						}
						System.out.println("File added: " + trackFile.getName());
						//wavTrack.add(track);
						wavTrackNum++;
						project.addTrack(track);
						
					}
					else {
						MIDITrack track = new MIDITrack(trackFile);
						track.setVolume(vol);
						System.out.println("File added: " + trackFile.getName());
						this.instrumentNumber = Integer.parseInt(recVarTok.nextToken());
						track.changeInstrument(this.instrumentNumber);
						midiTrackNum++;
						project.addTrack(track);
					}
				}
			}
			reader.close();
		} catch (javax.sound.sampled.LineUnavailableException e) {
			System.err.println("Line available when giving to WAVTrack");
		} catch (MidiUnavailableException e) {
			e.printStackTrace();
		} catch (InvalidMidiDataException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		try {
			File[] filesInDir = new File(directory + "/Recordings/").listFiles();
			for(File fileFound : filesInDir) 
			{
				if(filesKeep.contains(fileFound) == false) {
					if(fileFound.delete() == false) {
						System.err.println(fileFound.getAbsolutePath() + " failed to delete.");
					}
				}
			}
		} catch(Exception e) {
			e.printStackTrace();
		}
		char c = Character.forDigit(wavTrackNum, 10);
		outputFileA.add(new File(this.projectDir + "/Recordings/"
				+ m_outputFile + "A" + c + ".wav"));
		outputFileB.add(new File(this.projectDir + "/Recordings/"
				+ m_outputFile + "B" + c + ".wav"));
		c = Character.forDigit(midiTrackNum, 10);
		MIDIoutputFileA.add(new File(this.projectDir + "/Recordings/"
				+ m_outputFile + "A" + c + ".mid"));
		MIDIoutputFileB.add(new File(this.projectDir + "/Recordings/"
				+ m_outputFile + "B" + c + ".mid"));
		
		pressed = 0;
		recordingNum = 0;
		setup = 0;
		stop = false;
		rec = false;
		midi = false;
	}
	
	//save all the variables so Rec can be loaded up later
	public void save()
	{
		//Trying saving object directly to a file
		try {
			File recFile = new File(this.projectDir.getAbsolutePath() + File.separator + "list_tracks" + ".f8p");
			if(recFile.exists()) {
				recFile.delete();
			}
			recFile.createNewFile();
			
			String newline = System.getProperty("line.separator");

			BufferedWriter out = new BufferedWriter(new FileWriter(recFile));
			for(Track track : this.controller.getProject().getTracks())
			{
				if(track.getFile() == null) {
					Boolean[][] drum = track.getDrumMachine();
					if(drum != null)
					{
						File drumFile = new File(this.projectDir.getAbsolutePath() + 
								File.separator + "drum_machine" + ".f8p");
						ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(
								drumFile));
						stream.writeObject(drum);
						stream.close();
						out.write(drumFile.getAbsolutePath());
						out.write("," + track.getVolume());
						out.write("," + ((DrumMachineTrack) track).getKit());
						out.write(newline);
					}
					else {
						System.err.println("Invalid Drum Machine");
					}
				}
				else {
					String output = track.getFile().getAbsolutePath();
					output = output + "," + track.getVolume();
					if(track.getFile().getAbsolutePath().endsWith(".wav")){
						((WAVTrack)track).setFile(((WAVTrack)track).getOrigFile());
						output = output + "," + ((WAVTrack) track).getEffChainStr();
					}
					if(track.getType() == Type.MIDI) {
						output = output + "," + ((MIDITrack) track).getInstrumentNumber();
					}
					out.write(output);
					out.write(newline);
				}

			}
			out.close();
		}
		catch(Exception e) {
			e.printStackTrace();
		}
	}



	public void stopPress() {
		stop = true;
		rec = false;
	}

	public void trackDeleted(Track track) {
		if (track.getType() == Type.WAV) {
			wavTrackNum--;
		} else if (track.getType() == Type.MIDI){
			midiTrackNum--;
		}
	}

	// if record button is pressed
	public void recPress(MainWindow window, Boolean chooseInput) {
		if (rec == false) {
			rec = true;
			stop = false;
			if (setup == 0 || chooseInput) {
				recordSetUp(window);
			} else {
				startRecording();
			}
		} else
			rec = false;
	}

	public boolean isMIDI() {
		return midi;
	}

	// this gets called when someone presses keep
	// saves last recordings and gets it ready to start looping at the beginning
	// of the next loop
	public Track confirm() {
		Track output = null;
		// this condition is necessary as if someone presses keep during the
		// first recording of a layer
		// then there is no recording to save so java goes crazy
		if (recordingNum > 0) {
			if (midi == false) {
				List<File> outputFile, otherFile;
				
				if (current == 0) {
					outputFile = outputFileB;
					otherFile = outputFileA;
				} else {
					outputFile = outputFileA;
					otherFile = outputFileB;
				}
				
				// this checks whether to save A or B
				try {
					// makes a new track, sets up a clip for it, and sends
					// it the file
					WAVTrack track = new WAVTrack(
							(Clip) mixerPlay.getLine(info),
							outputFile.get(outputFile.size() - 1), timing);

					otherFile.get(otherFile.size() - 1).delete();
					output = track;
				} catch (javax.sound.sampled.LineUnavailableException e) {
					confirm();
					System.err.println("Line unavailable when giving to WAVTrack, trying again");
				} catch (IOException e) {
					e.printStackTrace();
				} catch (UnsupportedAudioFileException e) {
					e.printStackTrace();
				}
				
				wavTrackNum++;
				char c = Character.forDigit(wavTrackNum, 10);
				outputFileA.add(new File(this.projectDir + "/Recordings/"
						+ m_outputFile + "A" + c + ".wav"));
				outputFileB.add(new File(this.projectDir + "/Recordings/"
						+ m_outputFile + "B" + c + ".wav"));
			} else {
				try {
					if (current == 0) {
						output = new MIDITrack(MIDIoutputFileB
								.get(MIDIoutputFileB.size() - 1));
						MIDIoutputFileA.get(MIDIoutputFileA.size() - 1)
								.delete();
					} else {
						output = new MIDITrack(MIDIoutputFileA
									.get(MIDIoutputFileA.size() - 1));
						MIDIoutputFileB.get(MIDIoutputFileB.size() - 1)
								.delete();
					}
					((MIDITrack)  output).changeInstrument(instrumentNumber);
				} catch (MidiUnavailableException e) {
					e.printStackTrace();
				} catch (InvalidMidiDataException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
				midiTrackNum++;
				char c = Character.forDigit(midiTrackNum, 10);
				MIDIoutputFileA.add(new File(this.projectDir + "/Recordings/"
						+ m_outputFile + "A" + c + ".mid"));
				MIDIoutputFileB.add(new File(this.projectDir + "/Recordings/"
						+ m_outputFile + "B" + c + ".mid"));
			}
			pressed = 1;
			current = 0;
			recordingNum = -1;
		} else {
			JOptionPane.showMessageDialog(this.controller.getWindow().getFrame(), "Please wait until the end of the first recording of this layer.");
		}
		return output;
	}

	public void setTiming(LoopTiming newTiming) {
		this.timing = newTiming;
	}
	
	// when someone chooses an audioInput this then sets up the recorder
	public void audioInputChosen(InputMixer inputMixer) {
		try {
			targetDataLine = inputMixer.dataLine();
		} catch (javax.sound.sampled.LineUnavailableException e) {
			e.printStackTrace();
		}
		info = new DataLine.Info(Clip.class, inputMixer.getFormat());
		setup = 1;
		startRecording();
		midi = false;
		drumMachine = false;
		wav = true;
	}

	// when someone chooses an MIDIInput this then sets up the recorder
	public void MIDIinputChosen() throws MidiUnavailableException,
			InvalidMidiDataException {
		// set up midi bits and bobs
		if (midi) new RecMIDISelectInstrumentWindow (this.controller.getWindow(), synth.getDefaultSoundbank().getInstruments(), this);
		else {
			synth = MidiSystem.getSynthesizer();
			seq = MidiSystem.getSequencer(false);
			synth.open();
			seq.open();
			MidiDevice.Info[] deviceInfos = MidiSystem.getMidiDeviceInfo();
			MidiDevice.Info info = deviceInfos[0];
			MidiDevice inputDevice = MidiSystem.getMidiDevice(info);
			inputDevice.open();
			synthRcvr = synth.getReceiver();
			sequence = new Sequence(Sequence.PPQ, 1000);
			midiCurrent = sequence.createTrack();
			midiRecorder = new MIDIRecorder(midiCurrent, synthRcvr);
			Transmitter t = inputDevice.getTransmitter();
			t.setReceiver(midiRecorder);
			midi = true;
			new RecMIDISelectInstrumentWindow (this.controller.getWindow(), synth.getDefaultSoundbank().getInstruments(), this);
		}
		wav = false;
		drumMachine = false;
	}
	
	public void MIDISelectInstrument (int instrumentNum) {
		Instrument[] instruments  = synth.getDefaultSoundbank().getInstruments();
		//store instrumentNum in save file so the correct instrument can be reloaded
		instrumentNumber = instrumentNum;
		Instrument instrument = instruments[instrumentNum];
		Patch patch = instrument.getPatch();
	    MidiChannel[] channels = synth.getChannels();
	    for (int i=0; i<channels.length; i++) {
	        channels[i].programChange(patch.getBank(),
	        	    patch.getProgram());
	    }
		//startRecording();
	}
	
	
	public void closeLines() {
		if (seq != null) {
			seq.stop();
		    seq.close();
			synthRcvr.close();
		}
		if (targetDataLine != null) {
			targetDataLine.stop();
			targetDataLine.close();
		}
	}

	public void startRecording() {
		mainRecord = new rec2();
		stop = false;
		mainRecord.start();
	}

	// this sets up the recording basically
	public void recordSetUp(MainWindow window) {
		stop = true;
		new AudioInputWindow(window, Rec.getInputMixers(), this);
	}

	
	// the main recording function
	class rec2 extends Thread {
		public void run() {
			this.setPriority(MAX_PRIORITY);
			
			int j;
			// count in
			if(!midi) {
				try {
					targetDataLine.open(format);
					AudioRecorder capture = new AudioRecorder();
					// start thread
					
					capture.start();
				} catch (LineUnavailableException e2) {
					// TODO Auto-generated catch block
					e2.printStackTrace();
				}
			} 
			controller.getProject().countIn();
			if(!midi) targetDataLine.close();
			else {
				try {
					seq.setSequence(sequence);
				} catch (InvalidMidiDataException e1) {
					e1.printStackTrace();
				}
				midiRecorder.reset(midiCurrent);
			}
			while (!stop) {
				controller.playbackState(PlaybackEvent.State.RESET);
				controller.playbackState(PlaybackEvent.State.PLAYING);
				pressed = 0;
				// is not paused
				if (rec && !midi && wav) {
					// sets up a new audioCapture thread
					AudioRecorder capture = new AudioRecorder();
					// start thread
					capture.start();
					try {
						targetDataLine.open(format);
						controller.playbackState(PlaybackEvent.State.PLAYING);
					} catch (javax.sound.sampled.LineUnavailableException e) {
						e.printStackTrace();
					}
					// starts all the saved tracks
				}
				//else if (midi) midiRecorder.reset(midiCurrent);
				controller.getProject().stop();
				controller.getProject().play();
				if (rec && !midi && wav) {
					controller.playbackState(PlaybackEvent.State.NEW_BAR);
					controller.getProject().playDrumTrack();
					// recording line closed, thus the recording is stopped
					targetDataLine.close();
				} else if (rec) { 
					try {
						controller.playbackState(PlaybackEvent.State.NEW_BAR);
						controller.getProject().playDrumTrack();
						captureMIDI();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				recordingNum++;
				// if a keep was pressed then wavTrackNum needs to be
				// implemented for next recording
				if (pressed == 1) {
					current = 0;
				} else {
					if (current > 0) {
						current--;
					} else {
						current++;
					}
				}
			}
		}
	}

	// captures the audio from input
	class AudioRecorder extends Thread {
		public void run() {
			this.setPriority(MAX_PRIORITY);
			if (current == 0) {
				targetDataLine.start();
				try {
					AudioSystem.write(new AudioInputStream(targetDataLine),
							m_targetType,
							outputFileA.get(outputFileA.size() - 1));
				} catch (Exception e) {
				}
			} else if (current > 0) {
				targetDataLine.start();
				try {
					AudioSystem.write(new AudioInputStream(targetDataLine),
							m_targetType,
							outputFileB.get(outputFileB.size() - 1));
				} catch (Exception e) {
				}
			}
		}

	}

	void captureMIDI() throws IOException {
		if (current == 0)
			MidiSystem.write(sequence, 1,
					MIDIoutputFileA.get(MIDIoutputFileA.size() - 1));
		else
			MidiSystem.write(sequence, 1,
					MIDIoutputFileB.get(MIDIoutputFileB.size() - 1));
		seq.setMicrosecondPosition(0);
		try {
			sequence = new Sequence(Sequence.PPQ, 1000);
		} catch (InvalidMidiDataException e) {
			e.printStackTrace();
		}
		midiCurrent = sequence.createTrack();
		midiRecorder.reset(midiCurrent);
	}

}
